package com.junyidao.game.service;

import com.junyidao.game.Exception.BusinessException;
import com.junyidao.game.util.HttpUtil;
import com.junyidao.game.util.Md5Util;
import com.junyidao.game.util.StringUtil;
import org.dom4j.Document;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import java.util.*;

/**
 * Created by zzh on 2016/10/5.
 * 文件描述 ：微信支付
 */
@Service
@Transactional
public class WechatPayService {

    private static final Logger logger = LoggerFactory.getLogger(WechatPayService.class);

    private static final String WECHAT_PAY_URL = "https://api.mch.weixin.qq.com/pay/unifiedorder";
    private static final String WECHAT_QUERY_ORDER_URL = "https://api.mch.weixin.qq.com/pay/orderquery";

    /**
     * 微信公众号支付 交易类型：NATIVE
     *
     * @param appid            微信分配的公众账号ID
     * @param mch_id           微信支付分配的商户号
     * @param body             商品或支付单简要描述
     * @param out_trade_no     商户系统内部的订单号
     * @param total_fee        订单总金额，单位为分
     * @param spbill_create_ip APP和网页支付提交用户端ip
     * @param notify_url       接收微信支付异步通知回调地址，通知url必须为直接可访问的url，不能携带参数
     * @param productId        trade_type=NATIVE，此参数必传。此id为二维码中包含的商品ID，商户自行定义。
     * @return
     */
    public Map<String, String> unifiedOrder(String appid, String mch_id, String key, String body, String out_trade_no,
                                            Integer total_fee, String spbill_create_ip, String notify_url, String productId) {

        Map<String, String> ret = null;
        String nonce_str = StringUtil.randomString(20);
        //公共号支付
        String trade_type = "NATIVE";
        String sign = unifiedOrderSignature(appid, mch_id, key, body, out_trade_no, total_fee, spbill_create_ip, notify_url, nonce_str, trade_type, productId);
        if (StringUtils.isEmpty(sign)) {
            logger.info("发起统一支付失败！签名失败  out_trade_no=" + out_trade_no);
            BusinessException.throwException(1, "系统繁忙");
        }
        Document document = DocumentHelper.createDocument();// 创建根节点
        Element root = document.addElement("xml");
        Element appidXml = root.addElement("appid");
        appidXml.setText(appid);
        Element mch_idXml = root.addElement("mch_id");
        mch_idXml.setText(mch_id);
        Element bodyXml = root.addElement("body");
        bodyXml.setText(body);
        Element out_trade_noXml = root.addElement("out_trade_no");
        out_trade_noXml.setText(out_trade_no);
        Element total_feeXml = root.addElement("total_fee");
        total_feeXml.setText(String.valueOf(total_fee));
        Element spbill_create_ipXml = root.addElement("spbill_create_ip");
        spbill_create_ipXml.setText(spbill_create_ip);
        Element notify_urlXml = root.addElement("notify_url");
        notify_urlXml.setText(notify_url);
        Element openidXml = root.addElement("product_id");
        openidXml.setText(productId);
        Element nonce_strXml = root.addElement("nonce_str");
        nonce_strXml.setText(nonce_str);
        Element trade_typeXml = root.addElement("trade_type");
        trade_typeXml.setText(trade_type);
        Element signXml = root.addElement("sign");
        signXml.setText(sign);
        ret = HttpUtil.sendStringPostBackXml(WECHAT_PAY_URL, root.asXML());
        return ret;
    }

    /**
     * 微信公众号支付订单查询
     *
     * @param appid        微信分配的公众账号ID
     * @param mch_id       微信支付分配的商户号
     * @param out_trade_no 商户系统内部的订单号
     * @return
     */
    public Map<String, String> queryOrder(String appid, String mch_id, String out_trade_no, String key) {

        String nonce_str = StringUtil.randomString(20);
        Map<String, String> map = new HashMap<>();
        map.put("appid", appid);
        map.put("mch_id", mch_id);
        map.put("out_trade_no", out_trade_no);
        map.put("nonce_str", nonce_str);
        String sign = wechatSignature(map, key);
        if (StringUtils.isEmpty(sign)) {
            logger.info("发起统一支付失败！签名失败  out_trade_no=" + out_trade_no);
            BusinessException.throwException(1, "系统繁忙");
        }
        Document document = DocumentHelper.createDocument();// 创建根节点
        Element root = document.addElement("xml");
        Element appidXml = root.addElement("appid");
        appidXml.setText(appid);
        Element mch_idXml = root.addElement("mch_id");
        mch_idXml.setText(mch_id);
        Element out_trade_noXml = root.addElement("out_trade_no");
        out_trade_noXml.setText(out_trade_no);
        Element nonce_strXml = root.addElement("nonce_str");
        nonce_strXml.setText(nonce_str);
        Element signXml = root.addElement("sign");
        signXml.setText(sign);
        Map<String, String> ret = HttpUtil.sendStringPostBackXml(WECHAT_QUERY_ORDER_URL, root.asXML());
        return ret;
    }

    public String unifiedOrderSignature(String appid, String mch_id, String key, String body, String out_trade_no,
                                        Integer total_fee, String spbill_create_ip, String notify_url, String nonce_str, String trade_type, String productId) {

        String[] arr = new String[]{"appid", "mch_id", "nonce_str", "body", "out_trade_no", "total_fee", "spbill_create_ip", "notify_url", "trade_type", "product_id"};
        //字典序排序
        Arrays.sort(arr);
        Map<String, Object> map = new HashMap<>();
        map.put("appid", appid);
        map.put("mch_id", mch_id);
        map.put("body", body);
        map.put("out_trade_no", out_trade_no);
        map.put("total_fee", total_fee);
        map.put("spbill_create_ip", spbill_create_ip);
        map.put("notify_url", notify_url);
        map.put("product_id", productId);
        map.put("trade_type", trade_type);
        map.put("nonce_str", nonce_str);
        StringBuffer sb = new StringBuffer();
        for (String str : arr) {
            sb.append(str);
            sb.append("=");
            sb.append(map.get(str));
            sb.append("&");
        }
        sb.append("key=");
        sb.append(key);
        try {
            String signature = Md5Util.digestMD5(sb.toString());
            return signature;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return "";
    }

    /**
     * 微信支付结果通用通知 签名验证
     *
     * @param map 微信返回的xml存入maps
     * @return key 商户交易秘钥
     */
    public String wechatSignature(Map<String, String> map, String key) {
        List<String> list = new ArrayList<>();
        for (Map.Entry<String, String> entry : map.entrySet()) {
            list.add(entry.getKey());
        }
        Collections.sort(list);
        StringBuffer sb = new StringBuffer();
        for (String str : list) {
            //sign 微信返回的签名不参与签名验证
            if (str.equals("sign")) {
                continue;
            }
            if (StringUtils.isEmpty(map.get(str))) {
                continue;
            }
            sb.append(str);
            sb.append("=");
            sb.append(map.get(str));
            sb.append("&");
        }
        sb.append("key=");
        sb.append(key);
        try {
            String signature = Md5Util.digestMD5(sb.toString());
            return signature;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return "";
    }

}
